package com.example.springboottest.example.thread.dead;

import com.example.springboottest.util.Print;

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.lang.management.ThreadInfo;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * JDK 8中包含的ThreadMXBean接口提供了多种监视线程的方法，其 中包括两个死锁监测的方法，
 * 具体如下：
 * （1）findDeadlockedThreads 用于检测由于抢占JUC显式锁、Java内置锁引起死锁的线程。
 * （2）findMonitorDeadlockedThreads 仅仅用于检测由于抢占Java内置锁引起死锁的线程。
 */
public class DeadLockTest {
    //获取ThreadMXBean
    public static ThreadMXBean mbean = ManagementFactory.getThreadMXBean();

    public static void main(String[] args) {
        try {
            //创建可重入锁，默认的非公平锁
            Lock lock1 = new ReentrantLock();
            Lock lock2 = new ReentrantLock();

            //Runnable可执行实例1: 先抢占lock1， 再抢占 lock2
            Runnable r1 = () -> TwoLockDemo.useTowlockInterruptiblyLock(lock1, lock2);

            //Runnable可执行实例2: 先抢占lock2， 再抢占 lock1
            Runnable r2 = () -> TwoLockDemo.useTowlockInterruptiblyLock(lock2, lock1);
            Thread t1 = new Thread(r1, "thread-1");  //创建第1条线程
            Thread t2 = new Thread(r2, "thread-2");  //创建第2条线程
            t1.start(); //启动第1条线程
            t2.start(); //启动第2条线程

            //等待一段时间再执行死锁检测
            Thread.sleep(2000);
            Print.tcfo("等待2秒，开始死锁监测和处理");

            //获取到所有死锁线程的id
            long[] deadlockedThreads = mbean.findDeadlockedThreads();
            if (deadlockedThreads.length > 0) {
                Print.tcfo("发生了死锁，输出死锁线程的信息");
                //遍历数组获取所有的死锁线程详细堆栈信息并打印
                for (long pid : deadlockedThreads) {
                    //此方法获取不带有堆栈跟踪信息的线程数据
                    //hreadInfo threadInfo = mbean.getThreadInfo(pid);
                    //第二个参数指定转储多少项堆栈跟踪信息,设置为Integer.MAX_VALUE可以转储所有的堆栈跟踪信息
                    ThreadInfo threadInfo = mbean.getThreadInfo(pid, Integer.MAX_VALUE);
                    Print.tcfo(threadInfo);
                }
                Print.tcfo("中断一条线程，这里是线程：" + t1.getName());
                t1.interrupt();
            }
            Thread.sleep(Integer.MAX_VALUE);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
